package xcmg.device.util;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;
import xcmg.device.manager.config.RedisConfig;
import yb.ecp.fast.infra.infra.log.LogHelper;

import javax.annotation.PostConstruct;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author wangyong
 */
@Component
public class JedisUtils {

    // 常量定义
    private static final String REDIS_SCAN_CURSOR_START = "0";
    private static final long INCR_MAX_5DIGIT = 9998L;
    private static final long RESET_5DIGIT = 9999L;
    private static final long DEFAULT_EXPIRE_SECONDS = 24 * 60 * 60L;
    private static final int SCAN_BATCH_SIZE = 1000;

    @Autowired
    private RedisConfig config;

    private static JedisUtils jedisUtils;

    @Autowired
    private RedisTemplate redisTemplate;

    // Lua脚本（原子自增+重置）
    private static final String INCR_SCRIPT =
            "local current = redis.call('incr', KEYS[1])\n" +
                    "if current > tonumber(ARGV[1]) then\n" +
                    "    redis.call('del', KEYS[1])\n" +
                    "    return tonumber(ARGV[2])\n" +
                    "else\n" +
                    "    redis.call('expire', KEYS[1], ARGV[3])\n" +
                    "    return current\n" +
                    "end";

    @PostConstruct
    public void init() {
        jedisUtils = this;
        jedisUtils.config = this.config;
    }

    /**
     * 获取自增数（5位数循环）
     */
    public static Long incrByKey(String key) {
        return incrByKeyInternal(key, INCR_MAX_5DIGIT, RESET_5DIGIT);
    }


    /**
     * 自增核心方法（原子操作）
     */
    private static Long incrByKeyInternal(String key, long maxValue, long resetValue) {
        if (StringUtils.isBlank(key)) {
            return null;
        }
        Jedis jedis = null;
        try {
            JedisPool jedisPool = jedisUtils.config.jedisPool();
            jedis = jedisPool.getResource();
            // 执行Lua脚本
            Object result = jedis.eval(
                    INCR_SCRIPT,
                    1, // KEYS数量
                    key,
                    String.valueOf(maxValue),
                    String.valueOf(resetValue),
                    String.valueOf(DEFAULT_EXPIRE_SECONDS)
            );
            return (result != null) ? Long.parseLong(result.toString()) : null;
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 根据前缀批量删除（管道优化）
     */
    public static void batchDel(String keyPre) {
        if (StringUtils.isBlank(keyPre)) {
            return;
        }
        Jedis jedis = null;
        try {
            JedisPool jedisPool = jedisUtils.config.jedisPool();
            jedis = jedisPool.getResource();
            List<String> keyList = getScan(keyPre);
            Pipeline pipeline = jedis.pipelined();
            for (String key : keyList) {
                pipeline.del(key);
            }
            pipeline.sync(); // 批量提交命令
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * Scan扫描（连接复用+批量优化）
     */
    private static List<String> getScan(String keyPre) {
        List<String> list = new ArrayList<>();
        ScanParams params = new ScanParams();
        params.match(keyPre + "*");
        params.count(SCAN_BATCH_SIZE); // 扩大扫描批次
        String cursor = REDIS_SCAN_CURSOR_START;
        Jedis jedis = null;
        try {
            JedisPool jedisPool = jedisUtils.config.jedisPool();
            jedis = jedisPool.getResource(); // 外部获取连接
            do {
                ScanResult<String> scanResult = jedis.scan(cursor, params);
                list.addAll(scanResult.getResult());
                cursor = scanResult.getCursor();
            } while (!REDIS_SCAN_CURSOR_START.equals(cursor));
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return list;
    }

    /**
     * 判断缓存是否存在
     */
    @SuppressWarnings("unchecked")
    public boolean exists(final String key) {
        return Boolean.TRUE.equals(redisTemplate.hasKey(key));
    }

    /**
     * 读取缓存
     */
    @SuppressWarnings("unchecked")
    public Object get(final String key) {
        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
        return operations.get(key);
    }

    /**
     * 写入缓存（原子设置过期时间）
     */
    @SuppressWarnings("unchecked")
    public boolean set(final String key, Object value, Long expireTime) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            // 原子操作：set + expire
            operations.set(key, value, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            LogHelper.fatal("redis is error.", e);
        }
        return result;
    }

    /**
     * 删除缓存
     */
    @SuppressWarnings("unchecked")
    public void delete(final String key) {
        redisTemplate.delete(key);
    }
}
